﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using UtilZ.Dotnet.Ex.DataStruct;

namespace ConsoleApp.Test
{
    internal class TestObjectPool
    {
        public static void Test()
        {
            //TestBlockingCollection();
            TestConcurrentBag();
            //TestObjectPool1();
            TestSingleTypeObjectPool();
        }

        private static void TestSingleTypeObjectPool()
        {
            var manager = new SingleTypeObjectPool<TestObjectPoolItem>();
            int id = 1;
            for (int i = 0; i < 10; i++)
            {
                manager.Add(new TestObjectPoolItem(id, $"name{id}"));
                id++;
            }

            Task[] tasks = new Task[4];
            for (int i = 0; i < tasks.Length; i++)
            {
                tasks[i] = new Task(() =>
                {
                    TestObjectPoolItem item;
                    for (int j = 0; j < 100000000; j++)
                    {
                        if (manager.TryTake(out item))
                        {

                        }
                        else
                        {
                            item = new TestObjectPoolItem(id, $"name{id}");
                            Console.WriteLine("创建新项");
                            id++;
                        }

                        if (manager.Contains(item))
                        {
                            Console.WriteLine($"悲剧了.{item.ToString()}");
                        }
                        else
                        {
                            //
                            manager.Add(item);
                        }

                        //Thread.Sleep(1);
                    }
                });
                tasks[i].Start();
            }
            Task.WaitAll(tasks);

            manager.Dispose();
        }

        private static void TestObjectPool1()
        {
            ObjectPool cacheManager = new ObjectPool();

            TestObjectPool obj;
            if (cacheManager.TryTake<TestObjectPool>(out obj))
            {

            }
            else
            {
                obj = new TestObjectPool();
            }
            cacheManager.Add(obj);

            if (cacheManager.TryTake<TestObjectPool>(out obj))
            {

            }
            else
            {

            }
            cacheManager.Dispose();
        }

        private static void TestConcurrentBag()
        {
            ConcurrentBag<TestObjectPoolItem> items = new ConcurrentBag<TestObjectPoolItem>();
            TestObjectPoolItem value;
            if (items.TryTake(out value))
            {

            }
            else
            {

            }

            int id = 1;
            for (int i = 0; i < 5; i++)
            {
                items.Add(new TestObjectPoolItem(id, $"name{id}"));
                id++;
            }

            if (items.TryTake(out value))
            {

            }
            else
            {

            }


            int count0 = items.Count;

            TestObjectPoolItem[] ret1 = items.Take(1).ToArray();
            int count1 = items.Count;

            TestObjectPoolItem[] ret2 = items.Take(10).ToArray();
            int count2 = items.Count;
        }

        private static void TestBlockingCollection()
        {
            System.Collections.Concurrent.BlockingCollection<string> _blockingCollection = new System.Collections.Concurrent.BlockingCollection<string>();
            string item;
            var millisecondsTimeout = 10000;
            if (_blockingCollection.TryTake(out item, millisecondsTimeout, CancellationToken.None))
            {

            }
            else
            {

            }
        }

    }

    internal class TestObjectPoolItem
    {
        public int ID { get; set; }

        public string Name { get; set; }

        public TestObjectPoolItem(int id, string name)
        {
            this.ID = id;
            this.Name = name;
        }

        public override string ToString()
        {
            return $"{this.ID}      {this.Name}";
        }
    }
}
